﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Substrate;
using System.Diagnostics;
using System.Threading;
using System.IO;

namespace MCValidator
{
    public partial class MainForm : Form
    {
        private BetaWorld world;
        private IEnumerator<Substrate.Region> regionEnumerator = null;
        private TreeNode worldRoot = null;
        private Font fixedErrorFont;
        private bool WorldRequiresSave = false;

        public MainForm()
        {
            InitializeComponent();

            openFileDialog.InitialDirectory = "C:\\Minecraft\\server1.8\\broken";
            //openFileDialog.InitialDirectory = "C:\\Minecraft\\server\\world";
            //openFileDialog.InitialDirectory = "C:\\Minecraft\\server1.8\\world";
            fixedErrorFont = new Font(dataGridView1.DefaultCellStyle.Font, FontStyle.Strikeout);
        }

        private void MainForm_Shown(object sender, EventArgs e)
        {
            Application.DoEvents();
            start();
        }

        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            regionBGW.CancelAsync();
            // Wait for the BGW to finish
            while (regionBGW.IsBusy)
            {
                Application.DoEvents();
            }

            if (world != null && WorldRequiresSave)
            {
                if (MessageBox.Show("Save Changes?", "World", MessageBoxButtons.YesNo) == System.Windows.Forms.DialogResult.Yes)
                {
                    world.Save();
                }
            }
        }

        private void start()
        {
            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                string file = openFileDialog.FileName;
                Debug.Assert(Path.GetExtension(file) == ".dat");
                if (Path.GetExtension(file) == ".dat")
                {
                    world = BetaWorld.Open(file);
                    regionEnumerator = world.GetRegionManager().GetEnumerator();

                    dataGridView1.Rows.Clear();
                    treeView1.Nodes.Clear();

                    worldRoot = treeView1.Nodes.Add(file);
                    worldRoot.Expand();
                    progressBar.Visible = true;
                    progressLbl.Visible = true;
                    progressCancelButton.Visible = true;
                }

                // Kick off the background process
                regionBGW_RunWorkerCompleted(regionBGW, null);
            }
        }

        private void regionBGW_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            if (e.ProgressPercentage > 0)
            {
                // Avoid the slowly updating progress bar
                progressBar.Value = e.ProgressPercentage;
                progressBar.Value = e.ProgressPercentage - 1;
            }
            progressBar.Value = e.ProgressPercentage;
        }

        private void regionBGW_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            Application.DoEvents();

            // Finished this region
            BackgroundValidator worker = sender as BackgroundValidator;
            foreach (BackgroundValidator.Error err in worker.ErrorList)
            {
                int row = dataGridView1.Rows.Add();

                // store a reference to this error object
                dataGridView1.Rows[row].Tag = err;

                // Description
                dataGridView1.Rows[row].Cells[0].Value = err.Description;

                //Action
                DataGridViewComboBoxCell combo = dataGridView1.Rows[row].Cells["Action"] as DataGridViewComboBoxCell;
                foreach (BackgroundValidator.Action a in err.Actions)
                {
                    combo.Items.Add(a.Description);
                }
                // Default to the first added action.
                combo.Value = err.Actions[0].Description;

                // Fix
                DataGridViewButtonCell button = dataGridView1.Rows[row].Cells["Fix"] as DataGridViewButtonCell;
                button.Value = "Fix!";
            }
            // clear the error list for next time around
            worker.ErrorList.Clear();

            if (!(e!=null && e.Cancelled) && regionEnumerator.MoveNext())
            {
                // Eval the next
                Substrate.Region r = regionEnumerator.Current;
                progressLbl.Text = r.GetFileName();
                worldRoot.Nodes.Add(r.GetFileName());
                worldRoot.Expand();

                regionBGW.RunWorkerAsync(r);
            }
            else
            {
                // Finished all regions, 
                progressBar.Visible = false;
                progressLbl.Visible = false;
                progressCancelButton.Visible = false;
            }

        }

        private void progressCancelButton_ButtonClick(object sender, EventArgs e)
        {
            regionBGW.CancelAsync();
        }

        private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
        {
            // Ignore clicks that are not on button cells. 
            if (e.RowIndex < 0 ||
                e.ColumnIndex != dataGridView1.Columns["Fix"].Index ||
                dataGridView1.Rows[e.RowIndex].Cells["Fix"].Value as string == "Fixed")
                return;

            DataGridViewRow row = dataGridView1.Rows[e.RowIndex];
            string actionStr = row.Cells["Action"].Value as string;
            BackgroundValidator.Error err = row.Tag as BackgroundValidator.Error;
            BackgroundValidator.Action action = err.GetAction(actionStr);
            if (action.Perform())
            {
                Substrate.Region r = err.Region;
                if (r.RequiresSave)
                {
                    // Flag this file as needing saving
                    foreach (TreeNode n in worldRoot.Nodes)
                    {
                        if (n.Text == r.GetFileName())
                            n.Text = r.GetFileName() + " *";
                    }
                    WorldRequiresSave = true;
                }

                row.Cells["Message"].Style.Font = fixedErrorFont;
                row.Cells["Fix"].Value = "Fixed";
            }

        }

        private void regionBGW_DoWork(object sender, DoWorkEventArgs e)
        {

        }

    }
}
